원본 항목: Part 1-1. 삽입 계열 — 5. LDAP 삽입CWE-90repo 폴더: sd05_ldapinj/ (빌드·실행은 §3-1)
목표 시간: 1회차 15분 / 2회차 9분 / 3회차 6분mock_ldap 은 필터 문자열을 “정직하게” 평가하는 장난감 디렉터리다 — 진짜 LDAP처럼 * 를 만나면 전체를 매치시킨다.
이 드릴의 문서 구성 (SD01~SD58 공통)
① 요구사항서 — 어떤 코드가 뚫려 있고, 무엇을 만드나.
② pseudo code 템플릿 — Bad 와 Good 의 뼈대이고, 회차마다 가린다.
③ 테스트 코드 — 공격은 막히고 정상은 통과해야 끝이다.
④ 자주 하는 실수
⑤ 모범답안 — 맨 뒤에 접어 둔다.
int ldap_lookup_bad(const char *name);int ldap_lookup_good(const char *name);
신뢰 경계
값
출처
검증 없이 흘러가는 곳
name
외부(조회 폼)
LDAP 필터 문자열
공격 입력표
입력
Bad 결과(매칭 개수)
이유
alice (정상)
1
정상 동작
*
3
와일드카드로 디렉터리 전체가 노출된다
1-B. 변형 B — 부서 조회
(department=%s) 형태.
department 값에 )(uid=* 같은 필터 이스케이프 시도가 들어올 수 있음을 고려
1-C. 변형 C — 화이트리스트 대신 이스케이프로 전환
영숫자만 허용하는 대신, * ( ) \ NUL 다섯 문자를 LDAP RFC 방식(\2a, \28 등)으로 이스케이프하도록 바꾼다 — 한글 이름처럼 영숫자가 아닌 정상 입력도 통과시켜야 할 때 필요한 접근
2. pseudo code 템플릿 — 보고 쳐서 익힌다
사용법
변형별로 아래 pseudo code 를 소스 파일에 주석만 복사한다.
코드는 주석을 보고 내가 쓴다.
다 쓰면 [ ] 를 x 로 바꾼다.
막히면 §5 모범답안(A)의 해당 단계만 본다.
2-A. ldap_lookup_good — Level 1 (1회차, 전부 본다)
먼저 Bad 를 그대로 쳐서 §3 의 test_bad_is_vulnerable 이 통과하는지(= 실제로 뚫리는지) 확인한다.
그다음 Good 을 쓴다.
int ldap_lookup_bad(const char *name){ /* 1. char filter[64] * 2. snprintf(filter, sizeof(filter), "(name=%s)", name) ← 검증 없이 조립 * 3. return mock_ldap_search(filter) */}int ldap_lookup_good(const char *name){ /* [ ] 1. 지역변수 * char filter[64] */ /* [ ] 2. 검증 함수 is_safe_ldap_value(s) 를 먼저 만든다 * 길이가 0 이거나 32 초과 → 0 * isalnum((unsigned char)c) 가 아님 → 0 * 그 외 → 1 */ /* [ ] 3. 검증 (조립 전) * 실패 → return -1 */ /* [ ] 4. snprintf 로 "(name=%s)" 조립 */ /* [ ] 5. return mock_ldap_search(filter) */}
2-B. ldap_lookup_good — Level 2 (2회차, 번호와 제목만 본다)
int ldap_lookup_good(const char *name){ /* [ ] 1. 지역변수 */ /* [ ] 2. 검증 함수 is_safe_ldap_value(s) 를 먼저 만든다 */ /* [ ] 3. 검증 (조립 전) */ /* [ ] 4. snprintf 로 "(name=%s)" 조립 */ /* [ ] 5. return mock_ldap_search(filter) */}
2-C. ldap_lookup_good — Level 3 (3회차, 백지)
int ldap_lookup_good(const char *name){ /* 아무것도 안 본다. * §1 요구사항서와 §0 의 치환 규칙만 보고 친다. * * 막히면 아래만 찾아본다. * - `isalnum` 에 `unsigned char` 캐스팅 * - SD01 의 검증 함수와 같은 모양 */}
막혔을 때 찾는 순서
컴파일 에러가 나면 에러 문구를 본다.
unknown type name / implicit declaration 이면 include 누락이다.
man 3 <함수> 를 연다.
SYNOPSIS 맨 위의 #include 를 확인한다.
로직이 막히면 §3 테스트의 기대값을 먼저 읽는다.
공격 입력표(§1)와 테스트가 답이다.